package cn.moonspace.flowerowner.controller;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import cn.moonspace.flowerowner.exception.DriverException;
import cn.moonspace.flowerowner.form.DriverForm;
import cn.moonspace.flowerowner.form.RegulationForm;

@Controller
public class WeixinController extends BaseController {

	@RequestMapping(value = "/weixin", method = RequestMethod.GET)
	public void processGet(
            @RequestParam String signature, // 微信加密签名
			@RequestParam String timestamp, // 时间戳
            @RequestParam String nonce,     // 随机数
			@RequestParam String echostr,  // 随机字符串
            HttpServletResponse response
            ) throws IOException, NoSuchAlgorithmException {

        log.info("signature:" + signature);

        String token = "fanshion"; // 自定义令牌

		String[] strSet = new String[] { token, timestamp, nonce };
		Arrays.sort(strSet);

		String total = "";
		for (String string : strSet) {
			total = total + string;
		}

		// SHA-1加密实例
		MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
		sha1.update(total.getBytes());
		byte[] codedBytes = sha1.digest();
		String codedString = new BigInteger(1, codedBytes).toString(16);
		// 将加密后的字节数组转换成字符串。参见http://hi.baidu.com/aotori/item/c94813c4f15caa60f6c95d4a
		if (codedString.equals(signature)) {
			// 将加密的结果与请求参数中的signature比对，如果相同，原样返回echostr参数内容 
			OutputStream os = response.getOutputStream();
			BufferedWriter resBr = new BufferedWriter(new OutputStreamWriter(os));
			resBr.write(echostr);
			resBr.flush();
			resBr.close();
		} else {
            log.warn("不是微信服务器发来的请求，注意！");
        }

	}

    @RequestMapping(value = "/weixin", method = RequestMethod.POST)
    public void processPost(HttpServletRequest request, HttpServletResponse response)
            throws IOException, DocumentException, DriverException {

        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");

        // 解析微信服务器发来的消息
        InputStream inputStream = request.getInputStream();
        Map<String, String> map = new HashMap<String, String>();
        SAXReader reader = new SAXReader();
        Document document = reader.read(inputStream);
        Element root = document.getRootElement();

        log.info(document.asXML());

        List<Element> elementList = root.elements();
        for(Element e : elementList) {
            map.put(e.getName(),e.getText());
        }
        inputStream.close();

        // 处理消息
        String fromUserName = map.get("FromUserName");
        String toUserName = map.get("ToUserName");
        String msgType = map.get("MsgType");
        String content = map.get("Content");
        String msgId = map.get("MsgId");

        ResponseMessage message = new ResponseMessage();
        message.setToUserName(fromUserName);
        message.setFromUserName(toUserName);
        message.setMsgType("text");
        message.setCreateTime(new Date().getTime());

        if(msgType.equals("text")) {

            content = content.toUpperCase().trim();

            if(content.equals("1")) {
                // 显示查询违章命令格式
                StringBuilder r = new StringBuilder("请按以下格式输入：").append("\n");
                r.append("WZCX 车牌@发动机号").append("\n");
                r.append("如：WZCX 沪AB1234@123456").append("\n");
                message.setContent(r.toString());
            } else if(content.equals("2")) {
                // 显示扣分查询命令格式
                StringBuilder r = new StringBuilder("请按以下格式输入：").append("\n");
                r.append("KFCX 驾驶证档案编号").append("\n");
                r.append("如：KFCX 12345678").append("\n");
                message.setContent(r.toString());
            } else if(content.startsWith("WZCX")) {
                // 进行违章查询
                String[] s = content.replace("WZCX", "").trim().split("@");
                if(s.length != 2) {
                    message.setContent("输入信息有误！");
                } else {
                    RegulationForm form = new RegulationForm();
                    form.setArea(s[0].substring(0,1));
                    form.setCardNo(s[0].substring(1));
                    form.setCardType("02/小型汽车号牌");
                    form.setMachineNo(s[1].trim());
                    log.info("违章查询：" + form);
                    JSONObject result = regulationService.searchRegulation(form);
                    log.info("违章查询结果：" + result.toString());

                    // 解析查询结果
                    if(result.getString("error") == null || result.getString("error").isEmpty()) {
                        // 有违章信息，进行遍历
                        StringBuilder regulation = new StringBuilder();
                        JSONArray array = result.getJSONArray("result");
                        for(int i= 0; i < array.size(); i ++) {
                            JSONObject o = array.getJSONObject(i);
                            JSONArray a = o.getJSONArray("list");
                            for(int j = 0; j < o.getInt("count");j ++) {
                                JSONObject object = a.getJSONObject(j);
                                regulation.append("第" + (j + 1) + "条违章：").append("\n");
                                regulation.append(object.getString("time")).append("\n");
                                regulation.append(object.getString("address")).append("\n");
                                regulation.append(object.getString("content")).append("\n\n");
                            }
                        }
                        message.setContent(regulation.toString());
                    } else {
                        message.setContent(result.getString("error"));
                    }

                }

            } else if(content.startsWith("KFCX")) {
                // 进行扣分查询
                String driverNo = content.replace("KFCX", "").trim();
                DriverForm form = new DriverForm();
                form.setDriverNo(driverNo);
                log.info("扣分查询：" + form);
                JSONObject result = regulationService.searchDriver(form);
                log.info("扣分查询结果：" + result.toString());

                // 解析查询结果
                if(result.getString("error") == null || result.getString("error").isEmpty()) {
                    // 有违章信息，进行遍历
                    StringBuilder regulation = new StringBuilder();
                    regulation.append(result.getString("driverNo")).append("\n");
                    regulation.append(result.getString("driverName")).append("\n");
                    regulation.append(result.getString("sumScore")).append("\n\n");

                    JSONArray array = result.getJSONArray("items");
                    for(int i= 0; i < array.size(); i ++) {
                        JSONObject object = array.getJSONObject(i);
                        regulation.append("第" + (i + 1) + "条扣分：").append("\n");
                        regulation.append("车牌：" + object.getString("cardNo")).append("\n");
                        regulation.append("违规事件：" + object.getString("time")).append("\n");
                        regulation.append("违规内容：" + object.getString("content")).append("\n");
                        regulation.append("处罚：" + object.getString("penalty")).append("\n");
                        regulation.append("扣分：" + object.getString("score")).append("\n\n");
                    }
                    message.setContent(regulation.toString());
                } else {
                    message.setContent(result.getString("error"));
                }
            } else {
                // 显示帮助信息
                message.setContent(getMainMenu());
            }
        } else if(msgType.equalsIgnoreCase("event")) {
            String event = map.get("Event");
            if(event.equalsIgnoreCase("subscribe")) {
                // 事件处理Event是subscribe(订阅)的时候，发送欢迎及帮助信息
                message.setContent("感谢关注文明车主订阅号\n" + getMainMenu());
            }
        } else {
            //  未定义处理的消息类型
            log.warn(fromUserName + "发送的不是文本消息!" + msgType  );
            message.setContent(getMainMenu());
        }

        PrintWriter out = response.getWriter();
        out.print(message.toXmlString());
        out.close();

    }

    /**
     * 文字菜单
     *
     * @return
     */
    private static String getMainMenu() {
        StringBuffer buffer = new StringBuffer();
        buffer.append("请回复数字选择服务：").append("\n\n");
        buffer.append("1  违章查询").append("\n");
        buffer.append("2  扣分查询").append("\n\n");
        buffer.append("回复“?”显示此帮助菜单");
        return buffer.toString();
    }

}

/**
 * 响应用户的消息实体
 */
class ResponseMessage {

    private String ToUserName;
    private String FromUserName;
    private String MsgType;
    private String Content;
    private Long CreateTime;

    public String getToUserName() {
        return ToUserName;
    }

    public void setToUserName(String toUserName) {
        ToUserName = toUserName;
    }

    public String getFromUserName() {
        return FromUserName;
    }

    public void setFromUserName(String fromUserName) {
        FromUserName = fromUserName;
    }

    public String getMsgType() {
        return MsgType;
    }

    public void setMsgType(String msgType) {
        MsgType = msgType;
    }

    public String getContent() {
        return Content;
    }

    public void setContent(String content) {
        Content = content;
    }

    public Long getCreateTime() {
        return CreateTime;
    }

    public void setCreateTime(Long createTime) {
        CreateTime = createTime;
    }

    public String toXmlString() {
        StringBuffer r = new StringBuffer();
        r.append("<xml>");
        r.append("<ToUserName><![CDATA[");
        r.append(getToUserName());
        r.append("]]></ToUserName>");
        r.append("<FromUserName><![CDATA[");
        r.append(getFromUserName());
        r.append("]]></FromUserName>");
        r.append("<CreateTime>");
        r.append(getCreateTime());
        r.append("</CreateTime>");
        r.append("<MsgType><![CDATA[");
        r.append(getMsgType());
        r.append("]]></MsgType>");
        r.append("<Content><![CDATA[");
        r.append(getContent());
        r.append("]]></Content>");
        r.append("</xml>");
        return r.toString();
    }

}
